﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UFIDA.U9.Base;
using UFIDA.U9.Base.Doc;
using UFIDA.U9.Base.Organization;
using UFIDA.U9.Base.SOB;
using UFIDA.U9.CBO.MFG.CO;
using UFIDA.U9.CBO.SCM.Item;
using UFSoft.UBF.Business;
using UFSoft.UBF.PL;

namespace ufida.u9.ait.openapi.utils
{
    internal class EntityUtils
    {
        private static Dictionary<string,object> cache=new Dictionary<string, object>();
        static bool IsValid = false;

        static EntityUtils()
        {
            IsValid = U9Utils.IsValid();
        }

        public static string UpdateDocNo<T>(long id,string DocNo) where T : Doc
        {
            Type type = typeof(T);
            EntityQuery query = new EntityQuery(type.FullName);
            T entity = (T)query.FindByID(id);
            using (ISession session = Session.Open())
            {
                entity.DocNo = DocNo;
                session.Commit();
            }
            return entity.DocNo;
        }

        /// <summary>
        /// 获取料品分类
        /// </summary>
        /// <param name="code"></param>
        /// <param name="CategoryKind"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static ItemCategory getItemCategory(String code,int CategoryKind)
        {
            string key = $"getItemCategory-{code}-{CategoryKind}";

            try
            {
                if (cache.ContainsKey(key))
                    return cache[key] as ItemCategory;

                String opath = "";
                //查询料品分类
                switch (CategoryKind)
                {
                    case 0:
                        opath = $"Code={code} and CategorySystem.IsStock=1";
                        break;
                    case 1:
                        opath = $"Code={code} and CategorySystem.IsMFG=1";
                        break;
                    case 2:
                        opath = $"Code={code} and CategorySystem.IsSale=1";

                        break;
                    case 3:
                        opath = $"Code={code} and CategorySystem.IsSale=1";
                        break;
                    case 4:
                        opath = $"Code={code} and CategorySystem.IsMRP=1";
                        break;
                    case 5:
                        opath = $"Code={code} and CategorySystem.IsCost=1";
                        break;
                    case 6:
                        opath = $"Code={code} and CategorySystem.IsCredit=1";
                        break;
                    case 7:
                        opath = $"Code={code} and CategorySystem.IsPrice=1";
                        break;
                    case 8:
                        opath = $"Code={code} and CategorySystem.IsFI=1";
                        break;
                    default:
                        break;
                }
                ItemCategory cate = ItemCategory.Finder.Find(opath);
                if (cate == null)
                    throw new Exception($"查询料品分类失败,oql:{opath}");

                cache[key] = cate;
                return cate;
            }
            catch (Exception ex)
            {
                throw new Exception($"查询料品分类失败,错误消息:{ex.Message}", ex);
            }
        }

        public static CostField getCostField(String whcode)
        {
            string key = $"getCostField-{Context.LoginOrg.ID}-{whcode}";

            try
            {
                if (cache.ContainsKey(key))
                    return cache[key] as CostField;

                string path = $"Org.ID={Context.LoginOrg.ID} and Warehouse.Code='{whcode}'";
                CostFieldObject costFieldObject = CostFieldObject.Finder.Find(path);
                if (costFieldObject == null)
                    throw new Exception($"查找成本域失败,path:[{path}]");
                cache[key] = costFieldObject;
                return costFieldObject.CostField;
            }catch (Exception ex)
            {
                throw new Exception($"查找成本域失败,错误消息:{ex.Message}",ex);
            }
        }
        /// <summary>
        /// 依据日期获取当前组织的账簿会计期间
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static SOBAccountingPeriod getPostPeriod(DateTime date)
        {
            SetofBooks sob = getSetofBooks();
            String path = $"SetofBooks={sob.ID} and AccountPeriod.FromDate<='{date.ToString("d")}' and AccountPeriod.ToDate>='{date.ToShortDateString()}'";
            SOBAccountingPeriod period = SOBAccountingPeriod.Finder.Find(path);
            if (period == null)
                throw new Exception($"查询账簿会计期间失败!path:[{path}]");

            return period;
        }
        /// <summary>
        /// 获取当前组织的账簿
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static SetofBooks getSetofBooks()
        {
            Type type = typeof(SetofBooks);
            string key = $"{type.FullName}-{Context.LoginOrg.Code}";

            try
            {
                //取缓存
                if (cache.ContainsKey(key))
                {
                    return cache[key] as SetofBooks;
                }
                SetofBooks book = SetofBooks.Finder.Find($"Org.ID={Context.LoginOrg.ID} and SOBType=0");
                if (book == null)
                    throw new Exception($"查找主账簿失败,组织编码:[{Context.LoginOrg.Code}]");
                cache[key] = book;
                return book;
            }catch (Exception ex)
            {
                throw new Exception($"查找主账簿失败,错误消息:{ex.Message}",ex);
            }
        }

        public static bool HasProperty(Entity entity,string prop)
        {
            try
            {
                entity.GetValue(prop);
                return true;
            }catch (MetadataAccessException ex)
            {
                return false;
            }
        }
        public static BusinessEntity GetBusinessEntity(String fullName,string code)
        {
            string path = "";
            Entity entity = BusinessEntity.Create(fullName, null);
            if (HasProperty(entity,"DocNo"))
            {
                path = $"DocNo='{code}'";
            }else if (HasProperty(entity,"Code"))
            {
                path = $"Code='{code}'";
            }
            EntityQuery query = new EntityQuery(fullName);
            System.Collections.IList retlist = query.FindAll(path);
            if (retlist == null || retlist.Count == 0)
            {
                throw new Exception($"查询实体失败,实体名:[{fullName}],实体编码:[{code}]");
            }
            return (BusinessEntity)retlist[0];
        }

        public static T GetDocEntity<T>(string docno) where T : Doc
        {
            Type type = typeof(T);
            string path = "1=1";
            string key = $"{type.FullName}-{Context.LoginOrg.Code}-{docno}";

            try
            {
                if (docno == null || docno.Length == 0)
                    return null;

                //依据实体字段拼接where条件
                path = $"DocNo='{docno}' and Org.ID={Context.LoginOrg.ID}";

                //查询数据
                EntityQuery query = new EntityQuery(type.FullName);
                System.Collections.IList list = query.FindAll(path);
                if (list.Count == 0)
                {
                    throw new Exception($"查找数据为0! 实体:[{type.FullName}],单号:[{docno}]");
                }
                return list[0] as T;
            }
            catch (Exception ex)
            {
                throw new Exception($"查找单据失败! 实体:[{type.FullName}],单号:[{docno}]", ex);
            }
        }

        public static T GetEntityByCode<T>(String code,String field) where T : BusinessEntity
        {
            if (!IsValid)
            {
                return null;
            }

            Type type = typeof(T);
            string path = "1=1";
            string key = $"{type.FullName}-{Context.LoginOrg.Code}-{field}-{code}";
            System.Reflection.PropertyInfo[] props = type.GetProperties();

            try
            {
                if (code == null || code.Length == 0)
                    throw new Exception($"查询实体传入参数为空,实体:[{type.FullName}]");

                //取缓存
                if (cache.ContainsKey(key))
                {
                    return cache[key] as T;
                }

                //依据实体字段拼接where条件
                if (!props.Any(item =>
                {
                    return item.Name == field;
                }))
                {
                    throw new Exception($"实体:[{type.FullName}]不存在[{field}]字段");
                }
                path += $" and {field}='{code}'";

                if (props.Any(item =>
                {
                    return item.Name == "Org";
                }))
                {
                    path += $" and Org.ID='{Context.LoginOrg.ID}'";
                }

                //查询数据
                EntityQuery query = new EntityQuery(type.FullName);
                System.Collections.IList list = query.FindAll(path);
                if (list.Count == 0)
                {
                    throw new Exception($"查找数据为0! 实体:[{type.FullName}],字段[{field}],值:[{code}]");
                }
                cache[key] = list[0];
                return list[0] as T;
            }
            catch (Exception ex)
            {
                throw new Exception($"查找实体失败! 实体:[{type.FullName}],字段[{field}],值:[{code}]", ex);
            }
        }

        /// <summary>
        /// 依据Code字段翻译为ID字段,如果Code为空,则报错
        /// 这样要求该字段必填
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="code"></param>
        /// <returns></returns>
        public static T GetEntityByCode<T>(string code) where T : BusinessEntity
        {
            return GetEntityByCode<T>(code, "Code");
        }

        /// <summary>
        /// 依据通用档案DTO翻译为ID,如果DTO为空则不翻译
        /// 这样要求该字段可填
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dto">通用档案DTO</param>
        /// <returns></returns>
        public static T GetEntityByCode<T>(CopyOfCommonArchiveDataDTOData dto) where T : BusinessEntity
        {
            if (dto == null|| string.IsNullOrEmpty(dto.Code) ||dto.Code.Length==0)
                return default(T);
            return GetEntityByCode<T>(dto.Code, "Code");
        }

        public static T GetEntityByPath<T>(String path) where T : BusinessEntity
        {
            Type type = typeof(T);
            try
            {
                EntityQuery query = new EntityQuery(type.FullName);
                System.Collections.IList list = query.FindAll(path);
                if (list.Count == 0)
                {
                    throw new Exception($"查找不到数据,实体[{type.FullName}],path:[{path}]");
                }
                return list[0] as T;
            }catch (Exception ex)
            {
                throw new Exception($"查询实体出错,实体:[{type.FullName}],path:[{path}],错误消息:[{ex.Message}]",ex);
            }
        }
    }
}
